#ifndef  RECOVERY_STATUS_H
#define  RECOVERY_STATUS_H

#include <cstring>
#include <string>
#include <string_view>

namespace recovery {

class Status {
public:
    enum class Code : unsigned char {
        kOK = 0,
        kFailed = 1,
        kSubcode = 2,
        kErrno = 3,
        kInvalidArgument = 4,
		kArgumentNull = 5,
		kEndOfFile = 6, //will be removed 
        kMaxCode,
    };

    virtual ~Status();
    
    virtual bool isOK() const  { return _code == Code::kOK; }
	operator bool () const{
		return isOK();
	}
    static Status OK(){
        return Status();
    }

    bool isSubcode() const { return _code == Code::kSubcode;}
    bool isErrno() const { return _code == Code::kErrno;}
    bool isEndOfFile() const { return _code == Code::kEndOfFile;}



    virtual std::string what() const ;
    virtual Status toStatus(const std::string_view & msg = "") const;

    Status(const Status & right);
    Status & operator = (const Status & right);

    Status(Status && right);
    Status & operator =(Status && right);

    bool operator ==(const Status & right) const { return _code == right._code; }
    bool operator !=(const Status & right) const { return _code != right._code; } 


    bool isFailed() const { return _code == Code::kFailed;}
    bool isInvalidArgument() const { return _code == Code::kInvalidArgument;}
    bool isArgumentNull() const { return _code == Code::kArgumentNull;}

    static Status Failed(const std::string_view & msg = ""){
        return Status(Code::kFailed, msg);
    }
    static Status InvalidArgument(const std::string_view & msg = ""){
        return Status(Code::kInvalidArgument, msg);
    }
	static Status ArgumentNull(const std::string_view & msg = ""){
		return Status(Code::kArgumentNull, msg);
	}
	static Status Subcode(const std::string_view & msg = ""){
		return Status(Code::kSubcode, msg);
	}
	static Status Errno(const std::string_view & msg = ""){
		return Status(Code::kErrno, msg);
	}
	static Status EndOfFile(const std::string_view & msg = ""){
		return Status(Code::kEndOfFile, msg);
	}

	void state(const char * st) {
		_state = st;
	}
protected:
    Status(); // for performance
    Status(Code code, const std::string_view & msg="");

    virtual const char * getCodeMsg(Code code) const;
	const char * copy(const char * state, size_t size) const;

    const char * state() const {
        return _state;
    }
    Code code() const {
        return _code;
    }
    
private:

    Code _code;
    const char * _state;
};

inline Status::~Status(){
    delete [] _state;
}
inline Status::Status()
: _code(Code::kOK), _state(nullptr)
{
}
inline Status::Status(Code code, const std::string_view & msg)
: _code(code), _state(nullptr) 
{
    if(auto sz = msg.size(); sz > 0){
        _state = copy(msg.data(), sz);
    }
}

inline Status::Status(const Status & right)
: _code(right._code)
, _state(right._state == nullptr ? nullptr : copy(right._state, std::strlen(right._state)))
{
}
inline Status & Status::operator = (const Status & right){
	if(this != &right){
		_code = right._code;

		delete [] _state;
		_state = (right._state == nullptr ? nullptr : copy(right._state, std::strlen(right._state)));
	}
    return *this;
}

inline Status::Status(Status && right)
: _code(std::move(right._code))
, _state(right._state)
{
	right._state = nullptr;
}
inline Status & Status::operator = (Status && right){
	if(this != &right){
		_code = std::move(right._code);

		delete [] _state;
		_state = nullptr;
		std::swap(_state, right._state);
	}
    return *this;
}

}// end of namespace recovery


#endif   /* RECOVERY_STATUS_H */
